# -*- coding:utf-8 -*-
# title           :
# description     :
# author          :Python超人/三月三提供
# date            :2024-06-01
# link            :https://gitcode.net/pythoncr/
# python_version  :3.9
# ==============================================================================
import svgwrite

from 神笔码靓.神笔库.动画工具集 import 缩放动画关键帧, 旋转动画关键帧, 倾斜动画关键帧, 平移动画关键帧
from 神笔码靓.神笔库.定义集 import *
from 神笔码靓.神笔库.通用工具集 import *


@dataclass
class 元素位置信息:
    最小x: [float, int] = 0
    最小y: [float, int] = 0
    最大x: [float, int] = 0
    最大y: [float, int] = 0
    # 自定义的中心点
    中心点 = None

    @property
    def 中心x(self):
        if isinstance(self.中心点, tuple):
            return self.中心点[0]
        return (self.最小x + self.最大x) / 2

    @property
    def 中心y(self):
        if isinstance(self.中心点, tuple):
            return self.中心点[1]
        return (self.最小y + self.最大y) / 2

    @property
    def 宽(self):
        return self.最大x - self.最小x

    @property
    def 高(self):
        return self.最大y - self.最小y

    def __str__(self):
        return f"x:{self.最小x:.2f}~{self.最大x:.2f}  y:{self.最小y:.2f}~{self.最大y:.2f};\n" \
               f"中点:{self.中心x:.2f}, {self.中心y:.2f}  宽:{self.宽} 高:{self.高}"


class 元素:
    _id_no = 0
    元素缓存 = {}

    数值精确度 = 2
    数值精确度的属性 = ["x", "y", "cx", "cy"]

    @staticmethod
    def 元素缓存清除():
        元素.元素缓存 = {}

    # z_orders = []
    @staticmethod
    def 重置ID():
        元素._id_no = 0

    def 设置id(self, id_):
        self.设置属性值("id_", id_)
        return self

    def __init__(self, 高清图, 所属组: list):
        from 神笔码靓.神笔库.变换工具集 import 变换工具集
        from 神笔码靓.神笔库.样式工具集 import 样式工具集
        from 神笔码靓.神笔库.滤镜工具集 import 滤镜工具集
        from 神笔码靓.神笔库.动画工具集 import 动画工具集
        from 神笔码靓.神笔库 import 神笔绘图板

        self.svg_element = None
        self.元素属性 = {}
        self.元素处理列表 = []
        self.已有缓存 = 否
        self._不生成ID = False

        self.所属组 = 所属组
        self.所属组.append(self)

        self.dwg: svgwrite.Drawing = 高清图.dwg

        self.高清图: 神笔绘图板 = 高清图
        self.滤镜: 滤镜工具集 = 高清图.滤镜
        self.样式: 样式工具集 = 高清图.样式
        self.变换: 变换工具集 = 高清图.变换
        self.动画: 动画工具集 = 高清图.动画

    def 不生成ID(self):
        self._不生成ID = True
        return self

    def 创建组合(self, class_name: str = None, style=None,
             样式类名: str = None, 样式串: str = None, id_: str = None):
        return self.高清图.创建组合(元素列表=[self], class_name=class_name, style=class_name,
                             样式类名=样式类名, 样式串=样式串, id_=id_)

    def 创建模板(self, class_name: str = None, style=None,
             样式类名: str = None, 样式串: str = None, id_: str = None):
        return self.高清图.创建模板(元素列表=[self], class_name=class_name, style=class_name,
                             样式类名=样式类名, 样式串=样式串, id_=id_)

    def 添加到列表(self, 元素列表: list):
        if self not in 元素列表:
            元素列表.append(self)
        return self

    def 置前(self):
        # self.高清图.创建组合(元素列表=[self])
        self.所属组.remove(self)
        self.所属组.append(self)
        # 元素.z_orders.append(self)
        return self

    def 透明动画(self, 透明度循环集=[0.5, 1.0, 0.5], 持续时间: [float, int] = 1, 重复次数: int = None, 填充行为="remove"):
        self.元素处理预设(self.动画.透明, {
            "透明度循环集": 透明度循环集, "持续时间": 持续时间, "重复次数": 重复次数, "填充行为": 填充行为
        })
        return self

    def 虚线流动画(self, 方向: int = 1, 持续时间: [float, int] = 3, 周期: [float, int] = None,
              重复次数: int = None, 填充行为="remove"):
        """

        @param 方向:
        @param 持续时间:
        @param 周期:
        @param 重复次数:
        @param 填充行为:
        @return:
        """
        self.元素处理预设(self.动画.虚线流, {
            "方向": 方向, "持续时间": 持续时间, "周期": 周期, "重复次数": 重复次数, "填充行为": 填充行为
        })
        return self

    # def 自旋转(self, 旋转角度: float):  不支持
    #     self.设置属性值("自旋转", 旋转角度)
    #     return self

    def 平移动画(self, 开始时间=0, 持续时间=3,
             起点X=0, 起点Y=0, 终点X=0, 终点Y=-2000, 重复次数=None, 填充行为="freeze", 关键帧列表: list[平移动画关键帧] = []):
        """

        [使用样例]
        from 神笔码靓.神笔库.动画工具集 import 平移动画关键帧
        关键帧列表 = 列表()
        关键帧列表.添加元素(平移动画关键帧(时间点=0, 位置X=90, 位置Y=0))
        关键帧列表.添加元素(平移动画关键帧(时间点=0.8, 位置X=20, 位置Y=10))
        关键帧列表.添加元素(平移动画关键帧(时间点=1, 位置X=90, 位置Y=30))
        :param 开始时间: 指定动画开始的时间。可以是具体的时间值，也可以是一些特殊的值如"点击"或"鼠标悬停"等。
        :param 持续时间: 指定动画的持续时间，以秒为单位。
        :param 起点X: 指定变换的起始值。
        :param 起点Y: 指定变换的起始值。
        :param 终点X: 指定变换的结束值。
        :param 终点Y: 指定变换的结束值。
        :param 重复次数: 指定动画的重复次数。可以是具体的次数，也可以是"indefinite"表示无限次
        :param 填充行为: 指定动画的填充行为。可以是"remove"表示动画结束后还原到初始状态，也可以是"freeze"表示结束后保留动画最后的状态
        :return:
        """
        self.元素处理预设(self.动画.平移, {
            "开始时间": 开始时间, "持续时间": 持续时间, "起点X": 起点X, "起点Y": 起点Y,
            "终点X": 终点X, "终点Y": 终点Y, "重复次数": 重复次数, "填充行为": 填充行为, "关键帧列表": 关键帧列表
        })
        return self

    def 轨迹移动动画(self, 路径点列表, 开始时间=0, 持续时间=3, 重复次数=None, 填充行为="remove"):
        self.元素处理预设(self.动画.轨迹移动, {
            "开始时间": 开始时间, "持续时间": 持续时间, "路径点列表": 路径点列表, "重复次数": 重复次数, "填充行为": 填充行为
        })
        return self

    def 旋转动画(self, 开始时间=0, 持续时间=3,
             起始角=0, 起始旋转中心点=(0, 0), 结束角=360, 结束旋转中心点=None, 重复次数=None, 填充行为="remove",
             关键帧列表: list[旋转动画关键帧] = []):
        """

        [使用样例]
        from 神笔码靓.神笔库.动画工具集 import 旋转动画关键帧
        关键帧列表 = 列表()
        关键帧列表.添加元素(旋转动画关键帧(时间点=0, 旋转角=90, 旋转中心点=(0, 0)))
        关键帧列表.添加元素(旋转动画关键帧(时间点=0.8, 旋转角=20, 旋转中心点=(0, 0)))
        关键帧列表.添加元素(旋转动画关键帧(时间点=1, 旋转角=90, 旋转中心点=(0, 0)))
        :param 开始时间:
        :param 持续时间:
        :param 起始角:
        :param 起始旋转中心点:
        :param 结束角:
        :param 结束旋转中心点:
        :param 重复次数:
        :param 填充行为:
        :param 关键帧列表:
        :return:
        """
        if 起始旋转中心点 is None:
            起始旋转中心点 = (0, 0)
        if 结束旋转中心点 is None:
            结束旋转中心点 = 起始旋转中心点
        self.元素处理预设(self.动画.旋转, {
            "开始时间": 开始时间, "持续时间": 持续时间, "起始角": 起始角, "起始旋转中心点": 起始旋转中心点,
            "结束角": 结束角, "结束旋转中心点": 结束旋转中心点, "重复次数": 重复次数, "填充行为": 填充行为,
            "关键帧列表": 关键帧列表
        })
        return self

    def 缩放动画(self, 开始时间=0, 持续时间=3,
             开始缩放X=1, 开始缩放Y=1, 结束缩放X=-2, 结束缩放Y=2, 重复次数=None, 填充行为="remove",
             关键帧列表: list[缩放动画关键帧] = []):
        """

        [使用样例]
        from 神笔码靓.神笔库.动画工具集 import 缩放动画关键帧
        关键帧列表 = 列表()
        关键帧列表.添加元素(缩放动画关键帧(时间点=0, 缩放X=1, 缩放Y=2))
        关键帧列表.添加元素(缩放动画关键帧(时间点=0.8, 缩放X=2, 缩放Y=1))
        关键帧列表.添加元素(缩放动画关键帧(时间点=1, 缩放X=1, 缩放Y=2))
        :param 开始时间:
        :param 持续时间:
        :param 开始缩放X:
        :param 开始缩放Y:
        :param 结束缩放X:
        :param 结束缩放Y:
        :param 重复次数:
        :param 填充行为:
        :param 关键帧列表:
        :return:
        """
        self.元素处理预设(self.动画.缩放, {
            "开始时间": 开始时间, "持续时间": 持续时间,
            "开始缩放X": 开始缩放X, "开始缩放Y": 开始缩放Y, "结束缩放X": 结束缩放X, "结束缩放Y": 结束缩放Y,
            "重复次数": 重复次数, "填充行为": 填充行为, "关键帧列表": 关键帧列表
        })
        return self

    def 倾斜X动画(self, 开始时间=0, 持续时间=3, 起始倾斜角=0, 结束倾斜角=45, 重复次数=None, 填充行为="remove",
              关键帧列表: list[倾斜动画关键帧] = []):
        """

        [使用样例]
        from 神笔码靓.神笔库.动画工具集 import 倾斜动画关键帧
        关键帧列表 = 列表()
        关键帧列表.添加元素(倾斜动画关键帧(时间点=0, 倾斜角=90))
        关键帧列表.添加元素(倾斜动画关键帧(时间点=0.8, 倾斜角=20))
        关键帧列表.添加元素(倾斜动画关键帧(时间点=1, 倾斜角=90))
        :param 开始时间:
        :param 持续时间:
        :param 起始倾斜角:
        :param 结束倾斜角:
        :param 重复次数:
        :param 填充行为:
        :param 关键帧列表:
        :return:
        """
        self.元素处理预设(self.动画.倾斜X, {
            "开始时间": 开始时间, "持续时间": 持续时间, "起始倾斜角": 起始倾斜角, "结束倾斜角": 结束倾斜角,
            "重复次数": 重复次数, "填充行为": 填充行为, "关键帧列表": 关键帧列表
        })
        return self

    def 倾斜Y动画(self, 开始时间=0, 持续时间=3, 起始倾斜角=0, 结束倾斜角=45, 重复次数=None, 填充行为="remove",
              关键帧列表: list[倾斜动画关键帧] = []):
        """

        [使用样例]
        from 神笔码靓.神笔库.动画工具集 import 倾斜动画关键帧
        关键帧列表 = 列表()
        关键帧列表.添加元素(倾斜动画关键帧(时间点=0, 倾斜角=90))
        关键帧列表.添加元素(倾斜动画关键帧(时间点=0.8, 倾斜角=20))
        关键帧列表.添加元素(倾斜动画关键帧(时间点=1, 倾斜角=90))

        :param 开始时间:
        :param 持续时间:
        :param 起始倾斜角:
        :param 结束倾斜角:
        :param 重复次数:
        :param 填充行为:
        :param 关键帧列表:
        :return:
        """
        self.元素处理预设(self.动画.倾斜Y, {
            "开始时间": 开始时间, "持续时间": 持续时间, "起始倾斜角": 起始倾斜角, "结束倾斜角": 结束倾斜角,
            "重复次数": 重复次数, "填充行为": 填充行为, "关键帧列表": 关键帧列表
        })
        return self

    def 更换组(self, 组: list):
        if self.所属组 is 组:
            return

        if self.所属组 is not 空:
            self.所属组.remove(self)

        组.append(self)

    def 中心点计算(self, 元素位置: 元素位置信息):
        元素位置.中心点 = 元素位置.中心x, 元素位置.中心y
        return 元素位置.中心点

    def 获取元素范围(self):
        raise NotImplementedError("请实现 获取元素范围")

    def 获取元素列表范围(self, 属性名="元素列表"):
        P = self.获取属性值
        元素列表 = P(属性名)

        最小x = float('inf')
        最小y = float('inf')
        最大x = float('-inf')
        最大y = float('-inf')

        for 元素_ in 元素列表:
            最小x_, 最小y_, 最大x_, 最大y_ = 元素_.获取元素范围()

            if 最小x_ < 最小x:
                最小x = 最小x_

            if 最小y_ < 最小y:
                最小y = 最小y_

            if 最大x_ > 最大x:
                最大x = 最大x_

            if 最大y_ > 最大y:
                最大y = 最大y_

        return 最小x, 最小y, 最大x, 最大y

    def 获取路径点列表(self, 属性名="点列表"):
        P = self.获取属性值

        点列表 = P(属性名)
        路径点列表 = []
        from 神笔码靓.神笔库 import 神笔绘图板工具
        点列表 = 神笔绘图板工具.转SVG绘制路径命令(点列表)

        # ['M', 'm', 'L', 'l', 'H', 'h', 'V', 'v', 'C', 'c', 'S', 's', 'Q', 'q', 'T', 't', 'A', 'a', 'Z', 'z']
        for 点 in 点列表:
            if 点[0] in ["M", "m", "L", "l", "T", "t"]:
                顶点x, 顶点y = 点[1], 点[2]
            elif 点[0] in ["C", "c"]:
                # (x1, y1), (x2, y2), (x, y)
                顶点x, 顶点y = 点[5], 点[6]
            elif 点[0] in ["H", "h"]:
                顶点x = 点[1]
            elif 点[0] in ["V", "v"]:
                顶点y = 点[1]
            elif 点[0] in ["Q", "q", "S", "s"]:
                # (x1, y1), (x, y)
                顶点x, 顶点y = 点[3], 点[4]
            elif 点[0] in ["A", "a"]:
                # (rx, ry), x_axis_rotation, (large_arc_flag, sweep_flag), (x, y) =
                顶点x, 顶点y = 点[6], 点[7]
            elif 点[0] in ["Z", "z"]:
                pass
            else:
                顶点x, 顶点y = 点[0], 点[1]
            路径点列表.append((顶点x, 顶点y))

        return 路径点列表

    def 获取路径点列表范围(self, 属性名="点列表"):
        P = self.获取属性值

        点列表 = P(属性名)

        最小x = float('inf')
        最小y = float('inf')
        最大x = float('-inf')
        最大y = float('-inf')

        from 神笔码靓.神笔库 import 神笔绘图板工具
        点列表 = 神笔绘图板工具.转SVG绘制路径命令(点列表)

        # ['M', 'm', 'L', 'l', 'H', 'h', 'V', 'v', 'C', 'c', 'S', 's', 'Q', 'q', 'T', 't', 'A', 'a', 'Z', 'z']
        for 点 in 点列表:
            if 点[0] in ["M", "m", "L", "l", "T", "t"]:
                顶点x, 顶点y = 点[1], 点[2]
            elif 点[0] in ["C", "c"]:
                # (x1, y1), (x2, y2), (x, y)
                顶点x, 顶点y = 点[5], 点[6]
            elif 点[0] in ["H", "h"]:
                顶点x = 点[1]
            elif 点[0] in ["V", "v"]:
                顶点y = 点[1]
            elif 点[0] in ["Q", "q", "S", "s"]:
                # (x1, y1), (x, y)
                顶点x, 顶点y = 点[3], 点[4]
            elif 点[0] in ["A", "a"]:
                # (rx, ry), x_axis_rotation, (large_arc_flag, sweep_flag), (x, y) =
                顶点x, 顶点y = 点[6], 点[7]
            elif 点[0] in ["Z", "z"]:
                pass
            else:
                顶点x, 顶点y = 点[0], 点[1]

            if 顶点x < 最小x:
                最小x = 顶点x
            if 顶点x > 最大x:
                最大x = 顶点x
            if 顶点y < 最小y:
                最小y = 顶点y
            if 顶点y > 最大y:
                最大y = 顶点y

        return 最小x, 最小y, 最大x, 最大y

    def 获取位置信息(self) -> 元素位置信息:
        scale_x, scale_y, translate_x, translate_y = self.获取缩放平移值()
        最小x, 最小y, 最大x, 最大y = self.获取元素范围()

        元素位置_ = 元素位置信息(最小x=最小x * scale_x + translate_x, 最小y=最小y * scale_y + translate_y,
                       最大x=最大x * scale_x + translate_x, 最大y=最大y * scale_y + translate_y)
        元素位置_.中心点 = self.中心点计算(元素位置_)
        return 元素位置_

    # region 元素属性
    def 设置属性值(self, 属性名, 属性值):
        self.元素属性[属性名] = 属性值

    def 清除属性值(self, 属性名):
        if 属性名 in self.元素属性:
            del self.元素属性[属性名]

    def 设置样式(self, 样式):
        if 样式 is None:
            return
        self.元素属性["style"] = 样式
        return self

    def 设置样式类名(self, 样式类名):
        if 样式类名 is None:
            return
        self.元素属性["样式类名"] = 样式类名
        return self

    def 批量设置属性(self, **kwargs):
        for k in kwargs:
            self.元素属性[k] = kwargs[k]

    def 批量获取属性(self, 属性名列表, 默认值列表=[]):
        属性值列表 = []
        for idx, 属性名 in 索引列举(属性名列表):
            if idx < len(默认值列表):
                属性值 = self.获取属性值(属性名, 默认值列表[idx])
            else:
                属性值 = self.获取属性值(属性名)

            属性值列表.append(属性值)
        return 属性值列表

    def 获取属性值(self, 属性名, 默认值=空):
        if 属性名 not in self.元素属性:
            return 默认值
        属性值 = self.元素属性[属性名]

        if 属性值 is None:
            return 默认值

        if 属性名 in 元素.数值精确度的属性:
            return round(属性值, 元素.数值精确度)
        return 属性值

    def 获取颜色值(self, 属性名, 默认值=空):
        颜色值 = self.获取属性值(属性名, 默认值)

        if isinstance(颜色值, dict):  # 渐变色定义
            线性渐变 = 颜色值.get("线性渐变", None)
            径向渐变 = 颜色值.get("径向渐变", None)
            if 线性渐变:
                开始, 结束 = 线性渐变[0], 线性渐变[-1]
                开始位置 = 颜色值.get("开始位置", (0, 0))
                结束位置 = 颜色值.get("结束位置", (100, 100))
                颜色值 = self.高清图.创建线性渐变色(
                    开始位置=开始位置, 结束位置=结束位置,
                    开始颜色=开始.get("颜色", 颜色.黑色), 结束颜色=结束.get("颜色", 颜色.白色),
                    开始透明度=开始.get("透明度", 1.0), 结束透明度=结束.get("透明度", 1.0),
                    开始偏移=开始.get("偏移", 0), 结束偏移=结束.get("偏移", 0),
                    增加渐变中间点=线性渐变[1:-1]
                )
            elif 径向渐变:
                开始, 结束 = 径向渐变[0], 径向渐变[-1]
                渐变开始中心点 = 颜色值.get("开始中心点", (0, 0))
                渐变半径 = 颜色值.get("渐变半径", 100)
                渐变的焦点 = 颜色值.get("渐变的焦点", None)
                颜色值 = self.高清图.创建径向渐变色(
                    渐变开始中心点=渐变开始中心点, 渐变半径=渐变半径, 渐变的焦点=渐变的焦点,
                    开始颜色=开始.get("颜色", 颜色.黑色), 结束颜色=结束.get("颜色", 颜色.白色),
                    开始透明度=开始.get("透明度", 1.0), 结束透明度=结束.get("透明度", 1.0),
                    开始偏移=开始.get("偏移", 0), 结束偏移=结束.get("偏移", 0),
                    增加渐变中间点=径向渐变[1:-1]
                )

        if hasattr(颜色值, "svg_element"):
            颜色值 = getattr(颜色值, "svg_element")

        if hasattr(颜色值, "get_funciri"):
            颜色值 = getattr(颜色值, "get_funciri")()
        else:
            pass

        return 颜色值

    def 获取对象引用(self, 属性名, 默认值=空):
        对象 = self.获取属性值(属性名, 默认值)
        if hasattr(对象, "build_svg_element"):
            对象 = 对象.build_svg_element()

        if hasattr(对象, "get_iri"):
            引用值 = getattr(对象, "get_iri")()
        else:
            引用值 = 对象

        return 引用值

    # endregion

    @staticmethod
    def 生成元素id(perfix='mar3_pycr_', t=''):
        # id = f'{perfix}{t}_{str(self._id_no).rjust(5, "0")}'
        id_ = f'{perfix}{t}_{str(元素._id_no)}'
        元素._id_no += 1
        return id_

    def 重新生成Id(self, perfix='skip'):
        id_ = f'{perfix}_{str(元素._id_no)}'
        元素._id_no += 1
        self.ID = id_
        self.设置属性值("id_", id_)
        return self

    def 获取元素id(self, perfix='mar3_pycr_', t=''):
        if self._不生成ID:
            return None
        id_ = self.获取属性值("id_")
        if id_ is None:
            id_ = 元素.生成元素id(perfix=perfix, t=t)
        else:
            pass
        return id_.replace(" ", "")

    def 获取缩放平移值(self):
        scale_x, scale_y = 1, 1
        translate_x, translate_y = 0, 0
        for c, v in self.元素处理列表:
            if c.__name__ == "缩放":
                val_x, val_y = v["缩放X"], v["缩放Y"]
                val_y = 1 if val_y is None else val_y
                scale_x, scale_y = val_x * scale_x, val_y * scale_y
            elif c.__name__ == "平移":
                val_x, val_y = v["位移X"], v["位移Y"]
                val_y = 0 if val_y is None else val_y
                translate_x += val_x * scale_x
                translate_y += val_y * scale_y

        return scale_x, scale_y, translate_x, translate_y

    def 元素处理预设(self, 处理函数, 处理参数字典: dict):
        """

        :param 处理函数:
        :param 处理参数字典:
        :return:
        """
        self.元素处理列表.append((处理函数, 处理参数字典))

    def 元素处理预设重置(self, 处理函数名称):
        新元素处理列表 = []
        for 处理函数, 处理参数字典 in self.元素处理列表:
            if 处理函数.__name__ != 处理函数名称:
                新元素处理列表.append((处理函数, 处理参数字典))
        self.元素处理列表 = 新元素处理列表

    # region 滤镜
    def 模糊(self, 模糊度=2):
        self.元素处理预设(self.滤镜.模糊, {"模糊度": 模糊度})
        return self

    def 形态(self, 形态操作='膨胀', 操作值=2):
        """

        :param 形态操作: erode 侵蚀/腐蚀, dilate 膨胀
        :param 操作值:
        :return:
        """
        self.元素处理预设(self.滤镜.形态, {"形态操作": 形态操作, "操作值": 操作值})
        return self

    def 阴影(self, 偏移=(2, 2), 模糊度=2):
        self.元素处理预设(self.滤镜.阴影, {"偏移": 偏移, "模糊度": 模糊度})
        return self

    def 立体阴影(self, 偏移=(2, 2), 阴影模糊度=2, 灯光颜色=颜色.白色, 灯光位置=(-50, -100, 200)):
        self.元素处理预设(self.滤镜.立体阴影, {"偏移": 偏移, "阴影模糊度": 阴影模糊度, "灯光颜色": 灯光颜色, "灯光位置": 灯光位置})
        return self

    # def 投影(self, 偏移X=3, 偏移Y=3, 模糊度=5, 颜色=颜色.黑色, 透明度=0.5):
    #     self.元素处理预设(self.滤镜.投影, {"偏移X": 偏移X, "模糊度": 模糊度, "颜色": 颜色, "偏移Y": 偏移Y, "透明度": 透明度})
    #     return self

    def 扰动(self, 基频=0.05, 八度音阶数=2):
        self.元素处理预设(self.滤镜.扰动, {"基频": 基频, "八度音阶数": 八度音阶数})
        return self

    def 光照(self, 光源位置=(750, 300, 100), 光源颜色=颜色.白色):
        self.元素处理预设(self.滤镜.光照, {"光源位置": 光源位置, "光源颜色": 光源颜色})
        return self

    def 颜色滤镜(self, 颜色, x=0, y=0, 宽="100%", 高="100%", 透明度=0.5):
        self.元素处理预设(self.滤镜.颜色滤镜, {"颜色": 颜色, "x": x, "y": y, "宽": 宽, "高": 高, "透明度": 透明度})
        return self

    def 反色(self):
        self.元素处理预设(self.滤镜.反色, {})
        return self

    # endregion

    def 样式类名(self, 样式类名):
        self.设置属性值(属性名="样式类名", 属性值=样式类名)
        return self

    def 设置样式值(self, 样式名, 样式值):
        设置样式串 = f"{样式名}:{样式值}"
        已有样式串 = self.获取属性值(属性名="样式串")
        if 已有样式串 is None or str(已有样式串).strip(";") == "":
            样式串_ = 设置样式串
        else:
            if 设置样式串 in 已有样式串:
                return self

            if 样式名 in 已有样式串:
                import re
                样式串_ = re.sub(样式名 + r":\w+", 设置样式串, 已有样式串)
            else:
                样式串_ = str(已有样式串).strip(";") + ";" + 设置样式串

        self.设置属性值(属性名="样式串", 属性值=样式串_)
        return self

    def 隐藏(self):
        self.设置样式值("display", "none")
        return self

    def 显示(self):
        self.设置样式值("display", "block")
        return self

    def 样式字符串(self, 样式串, 覆盖=否):
        if 样式串 is None:
            样式串 = ""

        if 覆盖:
            样式串_ = 样式串
        else:
            已有样式串 = self.获取属性值(属性名="样式串")
            if 已有样式串 is None or str(已有样式串).strip(";") == "":
                样式串_ = 样式串
            else:
                样式串_ = str(已有样式串).strip(";") + ";" + 样式串

        self.设置属性值(属性名="样式串", 属性值=样式串_)
        return self

    # def 基于原图形旋转(self):
    #     """
    #     https://blog.csdn.net/wjw_java_android/article/details/105881775
    #     :return:
    #     """
    #     # self.样式字符串("transform-origin: center bottom;transform-box:fill-box")
    #     return self

    def SVG元素创建后触发(self, 元素_):
        pass

    def 构建SVG元素(self):
        raise NotImplementedError("请实现 构建SVG元素")

    def x(self, x):
        self.设置属性值("x", x)
        return self

    def y(self, y):
        self.设置属性值("y", y)
        return self

    def 位置(self, x, y):
        self.设置属性值("x", x)
        self.设置属性值("y", y)
        return self

    def 创建链接(self, 链接地址, 链接提示=None, 链接描述=None, 新开窗口=False, id_: str = None):
        self.高清图.创建链接(self, 链接地址=链接地址, 链接提示=链接提示, 链接描述=链接描述, 新开窗口=新开窗口, id_=id_)
        return self

    def 属性修改处理(self, SVG元素):
        P = self.获取属性值
        C = self.获取颜色值

        透明度 = P("透明度", 1)
        填充颜色 = C("填充颜色", 颜色.无)
        描边颜色 = C("描边颜色", 颜色.无)
        填充透明度 = P("填充透明度", 1)
        描边透明度 = P("描边透明度", 1)
        描边线帽样式 = P("描边线帽样式")
        描边线连接样式 = P("描边线连接样式")
        描边斜接限制 = P("描边斜接限制")
        _虚线起点偏移 = P("虚线起点偏移", None)

        if 透明度 != 1:
            SVG元素.attribs["opacity"] = 透明度

        if 填充透明度 != 1:
            SVG元素.attribs["fill-opacity"] = 填充透明度

        if 描边透明度 != 1:
            SVG元素.attribs["stroke-opacity"] = 描边透明度

        if 描边线帽样式 is not None:
            SVG元素.attribs["stroke-linecap"] = 描边线帽样式

        if 描边线连接样式 is not None:
            SVG元素.attribs["stroke-linejoin"] = 描边线连接样式

        if 描边斜接限制 is not None:
            SVG元素.attribs["stroke-miterlimit"] = 描边斜接限制

        if hasattr(SVG元素, "fill"):
            if 填充颜色 != 颜色.无:
                SVG元素.fill(填充颜色)

        if hasattr(SVG元素, "stroke"):
            if 描边颜色 != 颜色.无:
                SVG元素.stroke(描边颜色)

        _描边样式 = P("描边样式", None)
        if _描边样式 is not None:
            SVG元素['stroke-dasharray'] = _描边样式

        if _虚线起点偏移 is not None:
            SVG元素['stroke-dashoffset'] = _虚线起点偏移

    def 获取链接定位(self):
        attribs = self.build_svg_element().attribs
        return f"#{attribs['id']}"

    def build_svg_element(self):
        if self.svg_element is not None:
            return self.svg_element

        self.svg_element = self.构建SVG元素()
        if self.已有缓存:
            return self.svg_element

        for 处理函数, 处理参数字典 in self.元素处理列表:
            if 处理参数字典 is None:
                处理函数(self.svg_element)
            else:
                处理函数(self.svg_element, **处理参数字典)
        视图区 = self.获取属性值("视图区", None)
        if 视图区 is not None:
            minx, miny, width, height = 视图区
            self.svg_element.viewbox(minx=minx, miny=miny, width=width, height=height)
        style = self.获取属性值("style", None)
        if style is not None:
            self.svg_element.attribs["style"] = style

        return self.svg_element


class 样式可修改元素(元素):
    def 填充颜色(self, 颜色值, 透明度=1.0):
        self.设置属性值(属性名="填充颜色", 属性值=颜色值)
        if 透明度 < 1.0:
            self.填充透明度(透明度)
        return self

    def 填充透明度(self, 透明度):
        self.设置属性值(属性名="填充透明度", 属性值=透明度)
        return self

    def 描边颜色(self, 颜色值, 透明度=1.0):
        self.设置属性值(属性名="描边颜色", 属性值=颜色值)
        if 透明度 < 1.0:
            self.描边透明度(透明度)
        return self

    def 描边透明度(self, 透明度):
        self.设置属性值(属性名="描边透明度", 属性值=透明度)
        return self

    def 虚线起点偏移(self, 偏移量):
        self.设置属性值(属性名="虚线起点偏移", 属性值=偏移量)
        return self

    def 描边线端样式(self, 样式: 描边线端样式):
        """
        这个属性定义了线条末端的形状。它有三个可能的值：
        :param 样式:
                butt（默认值）：线条末端被截断，形成一个直角。
                round：线条末端被圆形化，形成一个半圆。
                square：线条末端被扩展成一个正方形。
        :return:
        """
        self.设置属性值(属性名="描边线帽样式", 属性值=样式)
        return self

    def 描边线连接样式(self, 样式: 描边线连接样式):
        """
        这个属性定义了两条线段相交时的形状。它有三个可能的值：
        :param 样式值:
        miter（默认值）：线段在交点处形成尖角，直到达到最大长度或角度限制。
        round：线段在交点处形成一个圆角。
        bevel：线段在交点处形成一个斜角。
        :return:
        """
        self.设置属性值(属性名="描边线连接样式", 属性值=样式)
        return self

    def 描边斜接限制(self, 限制值=4):
        """
        当 “描边线连接样式” 设置为 miter 时，此属性定义了斜接的最大长度。
        如果斜接的长度超过此限制，它将自动转换为 bevel 或 round 连接。
        :param 限制值:
        :return:
        """
        self.设置属性值(属性名="描边斜接限制", 属性值=限制值)
        return self

    def 描边样式(self, 样式值):
        self.设置属性值(属性名="描边样式", 属性值=样式值)
        return self

    def 描边宽度(self, 宽度值):
        self.设置属性值(属性名="描边宽度", 属性值=宽度值)
        return self

    def 透明度(self, 透明度):
        self.设置属性值(属性名="透明度", 属性值=透明度)
        return self

    def 无填充颜色(self):
        self.清除属性值(属性名="填充颜色")
        return self

    def 无描边颜色(self):
        self.清除属性值(属性名="描边颜色")
        return self

    def 无描边样式(self):
        self.清除属性值(属性名="无描边样式")
        return self

    def 无描边宽度(self):
        self.清除属性值(属性名="描边宽度")
        return self

    def 无透明度(self):
        self.清除属性值(属性名="透明度")
        return self

    def 属性修改处理(self, SVG元素):
        super(样式可修改元素, self).属性修改处理(SVG元素)
        P = self.获取属性值
        C = self.获取颜色值

        # 填充颜色 = C("填充颜色", 颜色.无)
        # 描边颜色 = C("描边颜色", 颜色.无)
        样式类名 = P("样式类名", None)
        描边宽度 = P("描边宽度", None)
        # 变换串 = P("变换串", None)
        样式串 = P("样式串", None)

        # if 填充颜色 != 颜色.无:
        #     SVG元素.fill(填充颜色)
        #
        # if 描边颜色 != 颜色.无:
        #     SVG元素.stroke(描边颜色)

        if 样式类名 is not None:
            SVG元素.attribs["class"] = 样式类名

        if 描边宽度 is not None:
            SVG元素.attribs["stroke-width"] = 描边宽度

        if 样式串 is not None:
            SVG元素.attribs["style"] = 样式串

        _描边样式 = P("描边样式")
        if _描边样式 is not None:
            SVG元素['stroke-dasharray'] = _描边样式


class 可变换元素(元素):

    def 透明度(self, 透明度):
        self.设置属性值(属性名="透明度", 属性值=透明度)
        return self

    # region 变换
    def 变换字符串(self, 变换串):
        self.设置属性值(属性名="变换串", 属性值=变换串)
        return self

    def 旋转(self, 旋转角度, 旋转中心点=None, 重置=False):
        if 旋转中心点 is None:
            位置信息 = self.获取位置信息()
            if math.isnan(位置信息.中心x) or math.isnan(位置信息.中心y):
                pass
            else:
                旋转中心点 = 位置信息.中心x, 位置信息.中心y

        scale_x, scale_y, translate_x, translate_y = self.获取缩放平移值()
        if 旋转中心点 is not None:
            旋转中心点 = 旋转中心点[0] / scale_x, 旋转中心点[1] / scale_y

        if 重置:
            self.元素处理预设重置("旋转")

        self.元素处理预设(self.变换.旋转, {"旋转角度": 旋转角度, "旋转中心点": 旋转中心点})
        return self

    def 显示中心点(self, 颜色=颜色.黑色):
        # scale_x, scale_y, translate_x, translate_y = self.获取缩放平移值()
        位置信息 = self.获取位置信息()
        中心点 = 位置信息.中心x, 位置信息.中心y
        self.高清图.十字(x=中心点[0], y=中心点[1], 颜色=颜色)
        return self

    def 缩放(self, 缩放X, 缩放Y=None, 重置=False):
        # if 缩放比例 is None or 缩放比例 == 1:
        #     return self
        if 缩放Y is None:
            缩放Y = 缩放X

        if 重置:
            self.元素处理预设重置("缩放")

        self.元素处理预设(self.变换.缩放, {"缩放X": 缩放X, "缩放Y": 缩放Y})

        # if isinstance(缩放比例, tuple):
        #     scale_x, scale_y = 缩放比例
        # else:
        #     scale_x, scale_y = 缩放比例, 缩放比例

        x = self.获取属性值("x")
        if x is not None:
            self.设置属性值("x", x / 缩放X)

        if 缩放Y is not None:
            y = self.获取属性值("y")
            if y is not None:
                self.设置属性值("y", y / 缩放Y)
        return self

    def 垂直翻转(self):
        self.元素处理预设(self.变换.垂直翻转, None)
        x = self.获取属性值("x", 0)
        self.设置属性值("x", -x)
        return self

    def 水平翻转(self):
        self.元素处理预设(self.变换.水平翻转, None)
        y = self.获取属性值("y", 0)
        self.设置属性值("y", -y)
        return self

    # def 视图区(self, 最小x坐标: float, 最小y坐标: float, 宽度: float, 高度: float):
    #     """
    #     viewBox属性定义了图形的坐标系统和初始视图区域。viewBox属性值包含四个数字，分别表示视图框的最小x坐标、最小y坐标、宽度和高度。
    #     :return:
    #     """
    #     self.设置属性值("视图区", f"{最小x坐标} {最小y坐标} {宽度} {高度}")
    #     return self

    def 平移(self, 位移X, 位移Y=None, 重置=False):
        if 位移Y is None:
            位移Y = 位移X

        if 重置:
            self.元素处理预设重置("平移")

        self.元素处理预设(self.变换.平移, {"位移X": 位移X, "位移Y": 位移Y})
        return self

    def 左移(self, 位移X, 重置=False):
        self.平移(-位移X, 0, 重置=重置)
        return self

    def 右移(self, 位移X, 重置=False):
        self.平移(位移X, 0, 重置=重置)
        return self

    def 上移(self, 位移Y, 重置=False):
        self.平移(0, -位移Y, 重置=重置)
        return self

    def 下移(self, 位移Y, 重置=False):
        self.平移(0, 位移Y, 重置=重置)
        return self

    def 矩阵(self, a, b, c, d, e, f, 重置=False):
        if 重置:
            self.元素处理预设重置("矩阵")
        self.元素处理预设(self.变换.矩阵, {"a": a, "b": b, "c": c, "d": d, "e": e, "f": f})
        return self

    def 倾斜X(self, 倾斜角度, 重置=False):
        if 重置:
            self.元素处理预设重置("倾斜X")
        self.元素处理预设(self.变换.倾斜X, {"倾斜角度": 倾斜角度})
        return self

    def 倾斜Y(self, 倾斜角度, 重置=False):
        if 重置:
            self.元素处理预设重置("倾斜Y")
        self.元素处理预设(self.变换.倾斜Y, {"倾斜角度": 倾斜角度})
        return self

    def 属性修改处理(self, SVG元素):
        super(可变换元素, self).属性修改处理(SVG元素)
        P = self.获取属性值

        变换串 = P("变换串", None)

        if 变换串 is not None:
            SVG元素.attribs["transform"] = 变换串

        # _自旋转 = P("自旋转", 0)  不支持
        # if _自旋转 != 0:
        #     SVG元素.attribs["rotate"] = _自旋转

    # endregion
